﻿using System;
using System.Drawing;

namespace RoboRallyAPI
{
	/// <summary>
	/// A player in the game. No Listmembers because we have to be visible to J#.
	/// </summary>
	public class Player 
	{

		/// <summary>
		/// What mode the player/robot is in.
		/// </summary>
		public enum MODE
		{
			/// <summary>
			/// Standard mode - it is moving around the board.
			/// </summary>
			ACTIVE,

			/// <summary>
			/// It is powered down - static on the board.
			/// </summary>
			POWER_DOWN,

			/// <summary>
			/// It is destroyed - will return next turn.
			/// </summary>
			DESTROYED,

			/// <summary>
			/// It is dead - lost all 3 life tokens.
			/// </summary>
			DEAD
		};

		/// <summary>
		/// The power down mode for this player.
		/// </summary>
		public enum POWER_MODE
		{
			/// <summary>
			/// Running (not down, not announced).
			/// </summary>
			UP,

			/// <summary>
			/// Announced, will power down at the end of the turn.
			/// </summary>
			ANNOUNCED,

			/// <summary>
			/// Powered down.
			/// </summary>
			DOWN
		};

		/// <summary>
		/// Create a player object. This is used during setup.
		/// </summary>
		/// <param name="guid">The unique identifier for this player.</param>
		/// <param name="archive">The archive square for this player.</param>
		/// <param name="robot">The robot for this player.</param>
		/// <param name="flags">The location of flags on the map. All will be marked not touched.</param>
		public Player(string guid, Point archive, Robot robot, Point [] flags)
		{
			Guid = guid;
			Cards = new Card[0];
			Lives = 3;
			Damage = 0;
			PowerMode = POWER_MODE.UP;
			Archive = archive;
			Robot = robot;
			FlagStates = new FlagState[flags.Length];
			for (int ind = 0; ind < flags.Length; ind++ )
				FlagStates[ind] = new FlagState(flags[ind]);
		}

		/// <summary>
		/// Copy constructor.
		/// </summary>
		/// <param name="src">Initialize with the values in this object.</param>
		public Player(Player src)
		{
			Guid = src.Guid;
			Lives = src.Lives;
			Damage = src.Damage;
			PowerMode = src.PowerMode;
			Archive = src.Archive;
			Robot = new Robot(src.Robot);

			// arrays (because of J# we can't use List).
			FlagStates = new FlagState[src.FlagStates.Length];
			for (int ind = 0; ind < src.FlagStates.Length; ind++)
				FlagStates[ind] = new FlagState(src.FlagStates[ind]);
			Cards = new Card[src.Cards.Length];
			for (int ind = 0; ind < src.Cards.Length; ind++)
				Cards[ind] = new Card(src.Cards[ind]);
		}

		/// <summary>
		/// The unique identifier for this player. This will remain constant for the length of the game (while the Player objects passed will
		/// change on every call).
		/// </summary>
		public string Guid { get; private set; }

		/// <summary>
		/// The Cards for this player.
		/// </summary>
		public Card[] Cards { get; set; }

		/// <summary>
		/// The number of lives this player has. Starts at 3 and when it is 0 the player is dead and removed from the board.
		/// </summary>
		public int Lives { get; protected set; }

		/// <summary>
		/// The level of damage this player has. Starts at 0, cards start locking at 5, and the player dies (Lives decreases by
		/// one) when it hits 10.
		/// </summary>
		public int Damage { get; protected set; }

		/// <summary>
		/// The location the players robot will re-enter on if it dies.
		/// </summary>
		public Point Archive { get; protected set; }

		/// <summary>
		/// The player's robot.
		/// </summary>
		public Robot Robot { get; private set; }

		/// <summary>
		/// The power down mode for the player.
		/// </summary>
		public POWER_MODE PowerMode { get; protected set; }

		/// <summary>
		/// The score for this player.
		/// </summary>
		public int Score
		{
			get
			{
				if (Mode == MODE.DEAD)
					return 0;
				if (HasWon)
					return 250;
				return FlagsTouched * 50 + Lives * 15 - Damage;
			}
		}

		/// <summary>
		/// The number of flags the player has touched. If it is 3 the player has won.
		/// </summary>
		public int FlagsTouched
		{
			get
			{
				int num = 0;
				foreach (FlagState fs in FlagStates)
					if (fs.Touched)
						num++;
				return num;
			}
		}

		/// <summary>
		/// true if the player has won.
		/// </summary>
		public bool HasWon
		{
			get
			{
				return FlagsTouched == FlagStates.Length;
			}
		}

		/// <summary>
		/// true if the player's robot is visible (on the map). False if it is dead or destroyed.
		/// </summary>
		public bool IsVisible
		{
			get { return Mode != MODE.DEAD && Mode != MODE.DESTROYED; }
		}

		/// <summary>
		/// The mode this player is in.
		/// </summary>
		public MODE Mode
		{
			get
			{
				if (Lives <= 0)
					return MODE.DEAD;
				if (Damage >= 10)
					return MODE.DESTROYED;
				if (PowerMode == POWER_MODE.DOWN)
					return MODE.POWER_DOWN;
				return MODE.ACTIVE;
			}
		}

		/// <summary>
		/// The number of the player's cards that are locked. Locked cards are the last N cards from the previous turn.
		/// </summary>
		public int NumLockedCards
		{
			get { return Math.Max(Damage - 4, 0); }
		}

		/// <summary>
		/// Where the flags are and if they've been touched.
		/// </summary>
		public FlagState[] FlagStates { get; protected set; }

		/// <summary>
		/// The state of the flags for a player.
		/// </summary>
		public class FlagState
		{
			/// <summary>
			/// Create the object. Flag is set to not touched.
			/// </summary>
			/// <param name="position">Which square the flag is on.</param>
			public FlagState(Point position)
			{
				Position = position;
				Touched = false;
			}

			/// <summary>
			/// Copy constructor.
			/// </summary>
			/// <param name="src">Initialize with the values in this object.</param>
			public FlagState(FlagState src)
			{
				Position = src.Position;
				Touched = src.Touched;
			}

			/// <summary>
			/// Which square the flag is on.
			/// </summary>
			public Point Position { get; protected set; }

			/// <summary>
			/// true if the flag has been touched. Once all 3 flags are touched a player has won.
			/// </summary>
			public bool Touched { get; set; }
		}
	}
}
